"""
@File    :   unified_response.py
@Time    :   2024/03/10 20:29:35
@Author  :   Qrj
@Email   :   923207736@qq.com
@description   :   统一的响应类
"""

import json
from datetime import datetime
from typing import Any, Mapping

from fastapi.responses import JSONResponse
from pydantic import BaseModel
from starlette.background import BackgroundTask

from src.utils.datetime import DatetimeUtil


class ApiJSONResponseEncoder(json.JSONEncoder):
    """Api的统一响应类使用的json编码器"""

    def default(self, out: Any) -> Any:
        # 进行单个元素类型转换
        if isinstance(out, BaseModel):
            # 将pydantic模型转换为dict
            return out.model_dump()
        if isinstance(out, datetime):
            # 转换datetime类型为时间戳(毫秒级)
            return DatetimeUtil.to_timestamp(out, level="millisecond", rounding=True)
        return super().default(out)


class ApiJSONResponse(JSONResponse):
    """基于JSONResponse的统一Api响应类"""

    # 这边将字段放在这边初始化, 是为了更加方便用于继承
    status_code: int = 200  # http响应码
    code: int = 200  # 服务响应状态码
    message: str = "请求成功"  # 响应信息
    success: bool = True  # 请求是否成功

    def __init__(
        self,
        *args,
        status_code: int | None = None,
        code: int | None = None,
        data: dict[str, Any] | None = None,
        message: str | None = None,
        success: bool | None = None,
        headers: Mapping[str, str] | None = None,
        media_type: str | None = None,
        background: BackgroundTask | None = None,
        **kwargs,
    ) -> None:
        # 根据传入的参数进行默认字段更新
        if status_code is not None:
            self.status_code = status_code
        if code is not None:
            self.code = code
        if message is not None:
            self.message = message
        if success is not None:
            self.success = success
        # 获取服务器当前时间的时间戳(毫秒级)
        timestamp = DatetimeUtil.to_timestamp(
            datetime.now(), level="millisecond", rounding=True
        )
        # 构建响应内容
        content = {
            "code": self.code,
            "data": data,
            "message": self.message,
            "success": self.success,
            "timestamp": timestamp,
        }
        # 如果有额外内容则传入响应内容
        if args:
            content["args"] = args
        if kwargs:
            content["kwargs"] = kwargs
        super().__init__(content, self.status_code, headers, media_type, background)

    def render(self, content: Any) -> bytes:
        return json.dumps(
            content,
            ensure_ascii=False,
            allow_nan=False,
            indent=None,
            separators=(",", ":"),
            cls=ApiJSONResponseEncoder,
        ).encode("utf-8")


class SuccessApiJSONResponse(ApiJSONResponse):
    """请求成功时使用的统一Api响应类"""

    status_code: int = 200  # http响应码
    code: int = 200  # 服务响应状态码
    message: str = "请求成功"  # 响应信息
    success: bool = True  # 请求是否成功


class FailApiJSONResponse(ApiJSONResponse):
    """请求成功时使用的统一Api响应类"""

    status_code: int = 200  # http响应码
    code: int = 400  # 服务响应状态码
    message: str = "请求失败"  # 响应信息
    success: bool = False  # 请求是否成功
